/**
 * 
 */
package com.moji.cyg.web.member;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import com.moji.cyg.biz.user.UserModel;
import com.moji.cyg.biz.user.UserService;
import com.moji.cyg.web.extend.session.SessionUtil;
import com.moji.cyg.web.model.CygWebConstant;
import com.moji.cyg.web.model.TimesPojo;

/**
 * @author shengli.caosl 2012-2-23 下午7:06:52
 */
@Controller
@RequestMapping("/member")
public class UserController {

    private static final Logger logger                  = LoggerFactory.getLogger(UserController.class);
    private static final String REG_NEED_PCODE          = "regNeedPCode";
    private static final String LOGIN_NEED_PCODE        = "loginNeedPCode";
    private static final int    WRONG_VALID_LOGIN_TIMES = 3;
    private static final int    WRONG_VALID_REG_TIMES   = 0;

    @Autowired
    private UserService         userService;

    @RequestMapping("/register.htm")
    public String regisater(@ModelAttribute("userForm") UserForm userForm, ModelMap map, HttpServletRequest request,
                            HttpServletResponse response) {
        checkAndAddRegTime(false, request, response, map);
        return "member/register";
    }

    @RequestMapping("/doRegister.htm")
    public String doRegister(@Valid @ModelAttribute("userForm") UserForm userForm, BindingResult result,
                             @ModelAttribute("pcode") String pcode, ModelMap map, HttpServletRequest request,
                             HttpServletResponse response) {
        if (checkAndAddRegTime(true, request, response, map) && !validPcCode(pcode, request)) {
            map.put("pcodeError", "验证码出错!");
            return "member/register";
        }
        if (!validRegisterParam(userForm)) {
            result.addError(new ObjectError("twicePassword", "两次输入的密码必须一致!"));
            return "member/register";
        }
        if (result.hasErrors()) {
            return "member/register";
        }
        boolean isSuccess = userService.createUser(userForm.getUserModel());
        if (!isSuccess) {
            return "error";
        }
        logger.info(userForm.toString());
        return loginSuccessAndRedirect(userForm.getUserName(), userForm.getPassword(), null, map, request, response);
    }

    @RequestMapping("/login.htm")
    public String login(@ModelAttribute("userForm") UserForm userForm, String rUrl, ModelMap map,
                        HttpServletRequest request, HttpServletResponse response) {
        User4SessionInfo userInfo = SessionUtil.getSession(request, CygWebConstant.SESSION_USER_KEY,
                                                           User4SessionInfo.class);
        // 已经登录的用户，直接跳转
        if (userInfo != null && userInfo.isEffective()) {
            rUrl = StringUtils.isNotBlank(rUrl) ? rUrl : CygWebConstant.PAGE_INDEX;
            map.clear();
            return "redirect:" + rUrl;
        }
        map.put("redirectUrl", rUrl);
        checkAndAddLoginTime(false, request, response, map);
        return "member/login";
    }

    @RequestMapping("/doLogin.htm")
    public String doLogin(@Valid @ModelAttribute("userForm") UserForm userForm, BindingResult result,
                          @ModelAttribute("pcode") String pcode, String redirectUrl, ModelMap map,
                          HttpServletRequest request, HttpServletResponse response) {
        if (checkAndAddLoginTime(true, request, response, map) && !validPcCode(pcode, request)) {
            map.put("pcodeError", "验证码出错!");
            return "member/login";
        }

        if (result.hasErrors()) {
            return "member/login";
        }
        redirectUrl = loginSuccessAndRedirect(userForm.getUserName(), userForm.getPassword(), redirectUrl, map,
                                              request, response);
        if (redirectUrl != null) {
            return redirectUrl;
        }
        map.put("errorMessage", "用户名密码错误");
        return "member/login";
    }

    private String loginSuccessAndRedirect(String userName, String password, String redirectUrl, ModelMap map,
                                           HttpServletRequest request, HttpServletResponse response) {
        UserModel userModel = userService.getUserByNameAndPassword(userName, password);
        if (userModel != null) {
            clearLoginTime(request, response, map);
            redirectUrl = StringUtils.isNotBlank(redirectUrl) ? redirectUrl : CygWebConstant.PAGE_INDEX;
            map.clear();
            User4SessionInfo userInfo = new User4SessionInfo();
            userInfo.setUm(userModel);
            SessionUtil.putRootDomainSession(response, CygWebConstant.SESSION_USER_KEY, userInfo, 5 * 24 * 60);
            return "redirect:" + redirectUrl;
        }
        return null;
    }

    private boolean validRegisterParam(UserForm user) {
        if (user == null) {
            return false;
        }
        if (!user.getPassword().equals(user.getTwicePassword())) {
            return false;
        }
        return true;
    }

    private boolean validPcCode(String pcCode, HttpServletRequest request) {
        String pcodeFromSession = SessionUtil.getSession(request, CygWebConstant.SESSION_PCODE_KEY, String.class);
        if (StringUtils.isBlank(pcCode) || StringUtils.isBlank(pcodeFromSession)) {
            return false;
        }
        if (pcCode.equalsIgnoreCase(pcodeFromSession)) {
            return true;
        }
        return false;
    }

    /**
     * 判断次数
     * 
     * @param isNeed 是否必须
     * @param request
     * @param response
     * @param map
     * @return
     */
    private boolean checkAndAddRegTime(boolean isNeed, HttpServletRequest request, HttpServletResponse response,
                                       ModelMap map) {
        TimesPojo timesPojo = SessionUtil.getSession(request, CygWebConstant.SESSION_TIMES_KEY, TimesPojo.class);
        if (timesPojo == null) {
            timesPojo = new TimesPojo(0, 1);
            SessionUtil.putLongLifeSession(response, CygWebConstant.SESSION_TIMES_KEY, timesPojo);
            if (isNeed) {
                throw new IllegalStateException("The cookie is not exist!");
            }
        }
        int registerTimes = timesPojo.getRegisterTimes();
        timesPojo.setRegisterTimes(timesPojo.getRegisterTimes() + 1);
        SessionUtil.putLongLifeSession(response, CygWebConstant.SESSION_TIMES_KEY, timesPojo);
        if (registerTimes >= WRONG_VALID_REG_TIMES + 1) {
            map.put(REG_NEED_PCODE, true);
            return true;
        } else if (registerTimes >= WRONG_VALID_REG_TIMES) {
            map.put(REG_NEED_PCODE, true);
            return false;
        }
        return false;
    }

    private boolean checkAndAddLoginTime(boolean isNeed, HttpServletRequest request, HttpServletResponse response,
                                         ModelMap map) {
        TimesPojo timesPojo = SessionUtil.getSession(request, CygWebConstant.SESSION_TIMES_KEY, TimesPojo.class);
        if (timesPojo == null) {
            timesPojo = new TimesPojo(1, 0);
            SessionUtil.putLongLifeSession(response, CygWebConstant.SESSION_TIMES_KEY, timesPojo);
            if (isNeed) {
                throw new IllegalStateException("The cookie is not exist!");
            }
        }
        int loginTimes = timesPojo.getLoginTimes();
        timesPojo.setLoginTimes(timesPojo.getLoginTimes() + 1);
        SessionUtil.putLongLifeSession(response, CygWebConstant.SESSION_TIMES_KEY, timesPojo);
        if (loginTimes >= WRONG_VALID_LOGIN_TIMES + 1) {
            map.put(LOGIN_NEED_PCODE, true);
            return true;
        } else if (loginTimes >= WRONG_VALID_LOGIN_TIMES) {
            map.put(LOGIN_NEED_PCODE, true);
            return false;
        }
        return false;
    }

    private void clearLoginTime(HttpServletRequest request, HttpServletResponse response, ModelMap map) {
        TimesPojo timesPojo = SessionUtil.getSession(request, CygWebConstant.SESSION_TIMES_KEY, TimesPojo.class);
        if (timesPojo != null) {
            timesPojo.setLoginTimes(0);
        }
        SessionUtil.putLongLifeSession(response, CygWebConstant.SESSION_TIMES_KEY, timesPojo);
    }
}
